using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Middleware
{
    /// <summary>
    /// 安全日志记录中间件
    /// 监控和记录安全相关事件
    /// </summary>
    public class SecurityLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<SecurityLoggingMiddleware> _logger;

        // 敏感端点配置
        private static readonly HashSet<string> SecurityEndpoints = new(StringComparer.OrdinalIgnoreCase)
        {
            "/api/auth/login",
            "/api/auth/logout",
            "/api/auth/refresh",
            "/api/auth/register",
            "/api/auth/reset-password",
            "/api/auth/change-password",
            "/api/auth/two-factor",
            "/api/users/permissions",
            "/api/roles",
            "/api/permissions",
            "/api/security",
            "/api/audit",
            "/api/system/settings"
        };

        // 可疑活动模式
        private static readonly Dictionary<string, string> SuspiciousPatterns = new()
        {
            { "sql", "SQL Injection" },
            { "script", "Cross-Site Scripting" },
            { "../", "Path Traversal" },
            { "eval(", "Code Injection" },
            { "exec(", "Command Injection" },
            { "system(", "System Call Injection" },
            { "union select", "SQL Union Injection" },
            { "drop table", "SQL Drop Attack" },
            { "delete from", "SQL Delete Attack" },
            { "insert into", "SQL Insert Attack" },
            { "<script>", "XSS Script Tag" },
            { "javascript:", "XSS JavaScript" },
            { "onload=", "XSS Event Handler" },
            { "onerror=", "XSS Error Handler" }
        };

        public SecurityLoggingMiddleware(RequestDelegate next, ILogger<SecurityLoggingMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var startTime = DateTime.UtcNow;
            var clientIp = GetClientIpAddress(context);
            var userAgent = context.Request.Headers.UserAgent.ToString();
            
            // 预先检查安全威胁
            var threatInfo = await AnalyzeThreatAsync(context);

            try
            {
                await _next(context);
            }
            finally
            {
                // 记录安全事件
                await LogSecurityEventAsync(context, startTime, threatInfo, clientIp, userAgent);
            }
        }

        private async Task<ThreatAnalysisResult> AnalyzeThreatAsync(HttpContext context)
        {
            var result = new ThreatAnalysisResult();

            try
            {
                // 检查请求路径
                AnalyzeRequestPath(context, result);

                // 检查查询参数
                AnalyzeQueryParameters(context, result);

                // 检查请求头
                AnalyzeRequestHeaders(context, result);

                // 检查请求体（如果适用）
                await AnalyzeRequestBodyAsync(context, result);

                // 评估威胁级别
                result.ThreatLevel = CalculateThreatLevel(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "分析安全威胁时发生错误");
                result.Errors.Add($"威胁分析错误: {ex.Message}");
            }

            return result;
        }

        private void AnalyzeRequestPath(HttpContext context, ThreatAnalysisResult result)
        {
            var path = context.Request.Path.Value ?? "";
            var method = context.Request.Method;

            // 检查是否为敏感端点
            if (IsSecurityEndpoint(path))
            {
                result.IsSensitiveEndpoint = true;
                result.SecurityEvents.Add("访问敏感端点");
            }

            // 检查路径遍历攻击
            if (path.Contains("../") || path.Contains("..\\"))
            {
                result.SuspiciousActivities.Add("路径遍历攻击尝试");
                result.RiskScore += 30;
            }

            // 检查SQL注入模式
            CheckSuspiciousPatterns(path, result);
        }

        private void AnalyzeQueryParameters(HttpContext context, ThreatAnalysisResult result)
        {
            foreach (var param in context.Request.Query)
            {
                var value = param.Value.ToString().ToLower();
                CheckSuspiciousPatterns(value, result);

                // 检查异常长的参数值
                if (value.Length > 1000)
                {
                    result.SuspiciousActivities.Add($"异常长的查询参数: {param.Key}");
                    result.RiskScore += 10;
                }
            }
        }

        private void AnalyzeRequestHeaders(HttpContext context, ThreatAnalysisResult result)
        {
            // 检查用户代理
            var userAgent = context.Request.Headers.UserAgent.ToString();
            if (string.IsNullOrEmpty(userAgent) || IsKnownBadUserAgent(userAgent))
            {
                result.SuspiciousActivities.Add("可疑的用户代理");
                result.RiskScore += 15;
            }

            // 检查Referer
            var referer = context.Request.Headers.Referer.ToString();
            if (!string.IsNullOrEmpty(referer) && IsExternalReferer(referer, context))
            {
                result.SuspiciousActivities.Add("外部Referer");
                result.RiskScore += 5;
            }

            // 检查授权头
            var authHeader = context.Request.Headers.Authorization.ToString();
            if (!string.IsNullOrEmpty(authHeader))
            {
                result.HasAuthenticatedAccess = true;
                
                // 检查JWT格式
                if (authHeader.StartsWith("Bearer ") && !IsValidJwtFormat(authHeader[7..]))
                {
                    result.SuspiciousActivities.Add("无效的JWT格式");
                    result.RiskScore += 20;
                }
            }
        }

        private async Task AnalyzeRequestBodyAsync(HttpContext context, ThreatAnalysisResult result)
        {
            if (context.Request.ContentLength > 0 && context.Request.ContentLength < 10240) // 限制10KB
            {
                try
                {
                    context.Request.EnableBuffering();
                    var body = await context.Request.GetRawBodyStringAsync();
                    if (!string.IsNullOrEmpty(body))
                    {
                        CheckSuspiciousPatterns(body.ToLower(), result);
                        result.HasRequestBody = true;
                    }
                    context.Request.Body.Position = 0;
                }
                catch (Exception ex)
                {
                    result.Errors.Add($"请求体分析错误: {ex.Message}");
                }
            }
        }

        private void CheckSuspiciousPatterns(string content, ThreatAnalysisResult result)
        {
            foreach (var pattern in SuspiciousPatterns)
            {
                if (content.Contains(pattern.Key))
                {
                    result.SuspiciousActivities.Add($"检测到{pattern.Value}模式");
                    result.RiskScore += 25;
                }
            }
        }

        private string CalculateThreatLevel(ThreatAnalysisResult result)
        {
            if (result.RiskScore >= 50)
                return "High";
            else if (result.RiskScore >= 20)
                return "Medium";
            else if (result.RiskScore > 0 || result.SuspiciousActivities.Any())
                return "Low";
            else
                return "None";
        }

        private bool IsSecurityEndpoint(string path)
        {
            return SecurityEndpoints.Any(endpoint => path.StartsWith(endpoint, StringComparison.OrdinalIgnoreCase));
        }

        private bool IsKnownBadUserAgent(string userAgent)
        {
            var badAgents = new[] { "sqlmap", "nikto", "nmap", "masscan", "curl", "wget" };
            return badAgents.Any(agent => userAgent.ToLower().Contains(agent));
        }

        private bool IsExternalReferer(string referer, HttpContext context)
        {
            try
            {
                var refererUri = new Uri(referer);
                var hostUri = new Uri($"{context.Request.Scheme}://{context.Request.Host}");
                return !string.Equals(refererUri.Host, hostUri.Host, StringComparison.OrdinalIgnoreCase);
            }
            catch
            {
                return true; // 如果无法解析，认为是外部的
            }
        }

        private bool IsValidJwtFormat(string jwt)
        {
            var parts = jwt.Split('.');
            return parts.Length == 3; // JWT应该有3个部分
        }

        private async Task LogSecurityEventAsync(HttpContext context, DateTime startTime, ThreatAnalysisResult threatInfo, string clientIp, string userAgent)
        {
            try
            {
                // 控制台日志记录
                LogSecurityToConsole(context, threatInfo, clientIp);

                // 数据库日志记录（现在可以启用）
                var securityLogService = context.RequestServices.GetService<ISecurityLogAppService>();
                if (securityLogService != null && ShouldLogToDatabase(threatInfo, context))
                {
                    var eventType = DetermineSecurityEventType(context, threatInfo);
                    var severity = MapThreatLevelToSeverity(threatInfo.ThreatLevel);
                    
                    var additionalData = new Dictionary<string, object>
                    {
                        ["ThreatAnalysis"] = threatInfo,
                        ["RequestPath"] = context.Request.Path.Value ?? "",
                        ["HttpMethod"] = context.Request.Method,
                        ["UserAgent"] = userAgent,
                        ["IpAddress"] = clientIp,
                        ["RequestHeaders"] = context.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()),
                        ["StatusCode"] = context.Response.StatusCode,
                        ["Duration"] = DateTime.UtcNow.Subtract(startTime).TotalMilliseconds
                    };

                    await securityLogService.LogSecurityEventAsync(
                        eventType: eventType,
                        message: GetSecurityMessage(context, threatInfo),
                        threatLevel: threatInfo.ThreatLevel,
                        userId: GetUserIdFromContext(context),
                        ipAddress: clientIp,
                        userAgent: userAgent,
                        additionalData: additionalData);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "记录安全事件时发生错误");
            }
        }

        private void LogSecurityToConsole(HttpContext context, ThreatAnalysisResult threatInfo, string clientIp)
        {
            if (threatInfo.ThreatLevel == "None" && !threatInfo.IsSensitiveEndpoint)
                return; // 跳过正常请求的安全日志

            var logLevel = threatInfo.ThreatLevel switch
            {
                "High" => LogLevel.Critical,
                "Medium" => LogLevel.Warning,
                "Low" => LogLevel.Information,
                _ => LogLevel.Debug
            };

            var message = $"安全事件: {context.Request.Method} {context.Request.Path} | " +
                         $"威胁级别: {threatInfo.ThreatLevel} | " +
                         $"风险分数: {threatInfo.RiskScore} | " +
                         $"IP: {clientIp} | " +
                         $"用户: {GetUserIdFromContext(context)} | " +
                         $"可疑活动: [{string.Join(", ", threatInfo.SuspiciousActivities)}]";

            _logger.Log(logLevel, message);
        }

        private bool ShouldLogToDatabase(ThreatAnalysisResult threatInfo, HttpContext context)
        {
            return threatInfo.ThreatLevel != "None" || 
                   threatInfo.IsSensitiveEndpoint || 
                   context.Response.StatusCode >= 400;
        }

        private string DetermineSecurityEventType(HttpContext context, ThreatAnalysisResult threatInfo)
        {
            if (context.Request.Path.Value?.Contains("/auth/") == true)
                return "Authentication";
            else if (threatInfo.SuspiciousActivities.Any(a => a.Contains("SQL")))
                return "SqlInjectionAttempt";
            else if (threatInfo.SuspiciousActivities.Any(a => a.Contains("XSS") || a.Contains("Script")))
                return "XssAttempt";
            else if (threatInfo.SuspiciousActivities.Any(a => a.Contains("路径遍历")))
                return "PathTraversalAttempt";
            else if (context.Response.StatusCode == 401)
                return "UnauthorizedAccess";
            else if (context.Response.StatusCode == 403)
                return "ForbiddenAccess";
            else
                return "GeneralSecurity";
        }

        private string MapThreatLevelToSeverity(string threatLevel)
        {
            return threatLevel switch
            {
                "High" => "Critical",
                "Medium" => "Warning",
                "Low" => "Information",
                _ => "Information"
            };
        }

        private string GetSecurityMessage(HttpContext context, ThreatAnalysisResult threatInfo)
        {
            if (threatInfo.SuspiciousActivities.Any())
            {
                return $"检测到可疑活动: {string.Join(", ", threatInfo.SuspiciousActivities)}";
            }
            else if (threatInfo.IsSensitiveEndpoint)
            {
                return $"访问敏感端点: {context.Request.Path}";
            }
            else
            {
                return $"安全事件监控: {context.Request.Method} {context.Request.Path}";
            }
        }

        #region 辅助方法

        private string? GetUserIdFromContext(HttpContext context)
        {
            return context.User?.FindFirst("sub")?.Value ?? 
                context.User?.FindFirst("user_id")?.Value ??
                context.User?.Identity?.Name;
        }

        private string? GetUserNameFromContext(HttpContext context)
        {
            return context.User?.FindFirst("name")?.Value ?? 
                context.User?.FindFirst("username")?.Value;
        }

        private string GetClientIpAddress(HttpContext context)
        {
            var xForwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xForwardedFor))
            {
                var ips = xForwardedFor.Split(',');
                return ips[0].Trim();
            }

            var xRealIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xRealIp))
            {
                return xRealIp;
            }

            return context.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
        }

        #endregion
    }

    /// <summary>
    /// 威胁分析结果
    /// </summary>
    public class ThreatAnalysisResult
    {
        public string ThreatLevel { get; set; } = "None";
        public int RiskScore { get; set; } = 0;
        public bool IsSensitiveEndpoint { get; set; } = false;
        public bool HasAuthenticatedAccess { get; set; } = false;
        public bool HasRequestBody { get; set; } = false;
        public List<string> SuspiciousActivities { get; set; } = new();
        public List<string> SecurityEvents { get; set; } = new();
        public List<string> Errors { get; set; } = new();
    }
}

/// <summary>
/// HttpContext扩展方法
/// </summary>
public static class HttpContextExtensions
{
    public static async Task<string> GetRawBodyStringAsync(this HttpRequest request)
    {
        using var reader = new System.IO.StreamReader(request.Body, System.Text.Encoding.UTF8, leaveOpen: true);
        return await reader.ReadToEndAsync();
    }
}
